/*
 * Copyright (C) 2005 Johan Maasing johan at zoom.nu Licensed under the Apache
 * License, Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package nu.zoom.swing.desktop.common.action;

import java.awt.event.ActionEvent;

import javax.swing.AbstractButton;

import nu.zoom.swing.desktop.WorkbenchFrame;
import nu.zoom.swing.desktop.WorkbenchFrameListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Utility method that helps in constructing Workbench frames that should be
 * singletons. A singleton frame is where the workbench should only contain one
 * instance of a particular frame. The visibility of the frame is toggled on or
 * off by this action.
 * 
 * @see nu.zoom.swing.desktop.component.ToggleFrameMenuItem
 */
public abstract class ToggleFrameAction<T extends AbstractButton> extends WorkbenchAction implements
		WorkbenchFrameListener {
	private static final long serialVersionUID = 3937995362715663967L;
	private Log log = LogFactory.getLog(getClass());
	private WorkbenchFrame frame = null;
	private T control;

	/**
	 * Construct a new toggle action.
	 * 
	 * @param control
	 *            The control that this action should be register as an action
	 *            listener for.
	 */
	public ToggleFrameAction(T control) {
		super();
		control.setAction(this);
		this.control = control;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		validateFrame();
		log.trace("Toggling frame");
		setVisible(!isVisible());
	}

	public T getControl() {
		return control;
	}

	/**
	 * Subclasses should construct the frame that this action will toggle.
	 * 
	 * @return The frame that the action should toggle. Must not return null.
	 */
	protected abstract WorkbenchFrame createFrame();

	/**
	 * Get the state of the frame (vsisible or hidden).
	 * 
	 * @return Returns the if the frame is visible.
	 */
	public boolean isVisible() {
		validateFrame();

		return frame.isVisible();
	}

	/**
	 * @param visible
	 *            The visible to set.
	 */
	public void setVisible(boolean visible) {
		validateFrame();
		control.setSelected(visible);
		frame.setVisible(visible);
	}

	private void validateFrame() {
		if (frame == null) {
			frame = createFrame();
			if (frame == null) {
				throw new IllegalStateException("createFrame must not return null");
			}
			frame.addFrameListener(this);
		}
	}

	@Override
	public void frameClosed(WorkbenchFrame frame) {
		log.trace("Frame closed event");
		frame.removeFrameListener(this);
		this.frame = null;
		control.setSelected(false);
	}

	@Override
	public void frameWillDispose(WorkbenchFrame frame) {
	}
}
